package com.opennetexam.manager.bussinessservice;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.openexam.openqti.openqtipaperquestion.*;
import com.openexam.openqti.qti.AssessmentItem;
import com.openexam.openqti.qti.AssessmentTest;
import com.opennetexam.manager.common.PageBean;
import com.opennetexam.manager.examinerbehavior_new.*;
import com.opennetexam.manager.examresult_new.AnswerRecord;
import com.opennetexam.manager.examresult_new.ExaminerBaseInfo;
import com.opennetexam.manager.examresult_new.ExaminerExamResult;
import com.opennetexam.manager.examresult_new.ExaminerPaperInfo;
import com.opennetexam.manager.mapper.*;
import com.opennetexam.manager.common.CommonFunction;
import com.opennetexam.manager.common.OperationResult;
import com.opennetexam.manager.common.TestPaperFromPackageGenerator;
import com.opennetexam.manager.databasemodel.*;
import com.opennetexam.manager.dto.*;
import com.opennetexam.manager.enums.*;
import com.opennetexam.manager.itemmodel.ICreaterFactory;
import com.opennetexam.manager.itemmodel.IHtmlCreater;
import com.opennetexam.manager.utils.*;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author 奶茶
 * Created by on 2017/12/8.
 */
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class ExamReportBusinessService {

    private static final Logger logger = Logger.getLogger(ExamReportBusinessService.class);

    @Autowired
    private ExamineeArrangeMapper examineeArrangeMapper;
    @Autowired
    private ExamReportMapper examReportMapper;
    @Autowired
    private ExamingMoniterLogMapper examingMoniterLogMapper;
    @Autowired
    private ExamPlanInfoMapper examPlanInfoMapper;
    @Autowired
    private FreeExamReportMapper freeExamReportMapper;
    @Autowired
    private ExamPaperMapper examPaperMapper;

    @Value("${PackageKEY}")
    private String packageKey;

    private static JAXBContext assessmentItemJAXBContext;
    static {
        try {
            assessmentItemJAXBContext = JAXBContext.newInstance(AssessmentItem.class);
        } catch (JAXBException e) {
            logger.error("JAXBException",e);
        }
    }


    /**
     * 考试计划列表
     * @param appId
     * @param siteId
     * @param planType
     * @return
     */
    public List<ExamPlanViewModel> findExamPlanList(String appId, String siteId, Short planType){
        //List<ExamCount> examCountList = examineeArrangeMapper.findExamCountList();
        ////根据考试计划ID去重
        //examCountList = CommonFunction.examCountsDistinct(examCountList);

        List<ExamPlanViewModel> examPlanViewModelList = examineeArrangeMapper.findExamPlanViewModelBySomeWhere(appId, siteId, planType,null);


        if(examPlanViewModelList != null && !examPlanViewModelList.isEmpty()){
            for (int i=0;i<examPlanViewModelList.size();i++){
                if(DateUtil.convertStringToDate(examPlanViewModelList.get(i).getEndTime()).getTime() < System.currentTimeMillis()){
                    examPlanViewModelList.get(i).setEnd(true);
                }else{
                    examPlanViewModelList.get(i).setEnd(false);
                }
                //ExamCount examCount = CommonFunction.examCountsFirstOrDefault(appId, examPlanViewModelList.get(i).getBatchId(), examCountList);
                examPlanViewModelList.get(i).setExamCount(examPlanViewModelList.get(i).getExamSubjectCount());
            }
        }
        return examPlanViewModelList;
    }

    /**
     * 获取签到数据
     * @param adminInfo
     * @param planId
     * @return
     */
    public List<Map<String,Object>> getSignInReport(AdminInfo adminInfo,String planId){
       return examReportMapper.getSignInReport(adminInfo.getAppID(),planId);
    }

    /**
     * 根据考场计划，考场，场次，科目，考生状态获取监考报告列表
     * @param planId
     * @param roomId
     * @param sceneId
     * @param subjectId
     * @param reportState
     * @param appId
     * @return
     */
    public List<ExamcaseViewModel> findExamReportList(String planId, String roomId, String sceneId, String subjectId, Integer reportState, String appId){
        //获取监考报告列表
        List<ExamcaseViewModel> examcaseViewModels = examReportMapper.findExamReportListBySomeWhere(planId, roomId, sceneId, subjectId, reportState, appId);
        //获取缺考人数
        List<Map<String, Object>> absenceCountList = examReportMapper.findAbsenceOrAllCountList(planId, roomId, sceneId, subjectId, appId, ExamManagerState.Discipline.getPrefix());
        List<Map<String, Object>> allCountList = examReportMapper.findAbsenceOrAllCountList(planId, roomId, sceneId, subjectId, appId, null);

        for (ExamcaseViewModel examcaseViewModel:examcaseViewModels) {
            Map<String, Object> map = CommonFunction.countFirstOrDefault(absenceCountList, examcaseViewModel.getExamSubjectId(), null);
            Map<String, Object> map1 = CommonFunction.countFirstOrDefault(allCountList, examcaseViewModel.getExamSubjectId(), appId);

            examcaseViewModel.setAbsentCount(map == null ? 0 : absenceCountList.size());
            examcaseViewModel.setAllCount(map1 == null ? 0 : allCountList.size());
        }
        return examcaseViewModels;
    }

    /**
     * 根据考试计划，场次，科目，考场来获取对应考生考试监控列表
     * @param planId 考试计划ID
     * @param roomId 考场ID
     * @param sceneId 场次ID
     * @param subjectId 科目ID
     * @param appId
     * @param siteId
     * @return
     */
    public List<ExamingMonitorViewModel> findExamingMonitorList(String planId, String roomId, String sceneId, String subjectId, String appId, String siteId,ExamAdminInfoDTO adminInfo){
        List<ExamingMonitorViewModel> retList = new ArrayList<>();
        List<Map<String, Object>> examingMonitorList = examReportMapper.findExamingMonitorList(planId, roomId, sceneId, subjectId, appId, siteId);

        for (Map<String, Object> map:examingMonitorList){

            ExamingMonitorViewModel model = new ExamingMonitorViewModel();
            model.setId(map.get("ID").toString());
            model.setExamPaperID(map.get("ExamPaperID").toString());
            model.setSourceExamPaperID((String) map.get("sourceExamPaperID"));
            model.setSubmitType((Integer) map.get("SubmitType"));
            model.setLoginTime(map.get("LoginTime").toString());
            model.setRelBeginTime(map.get("RelBeginTime").toString());
            model.setExamEndTime(map.get("ExamEndTime").toString());
            model.setSysState((Integer) map.get("SysState"));
            model.setDelayedTime((Integer) map.get("DelayedTime"));
            model.setPlanBeginTime(map.get("PlanBeginTime").toString());
            model.setRegister((Integer) map.get("Register"));
            model.setRemark((String) map.get("Remark"));
            model.setRegisterTime(map.get("RegisterTime").toString());

            model.setCertificateNo((String) map.get("CertificateNo"));
            model.setExamineeID((String) map.get("ExamineeID"));
            model.setExamineeName((String) map.get("ExamineeName"));
            model.setExamCardNo((String) map.get("ExamCardNo"));
            model.setExamPlanInfoID(planId);
            model.setDeploymentMode(Integer.parseInt(map.get("deploymentMode").toString()));
            model.setExamPlanInfoName((String) map.get("ExamPlanInfoName"));
            model.setExamSceneID((String) map.get("ExamSceneID"));
            model.setExamSceneName((String) map.get("ExamSceneName"));
            model.setExamRoomID((String) map.get("ExamRoomID"));
            model.setExamRoomName((String) map.get("ExamRoomName"));
            model.setExamSiteID(siteId);
            model.setExamSiteName((String) map.get("ExamSiteName"));
            model.setExamSubjectID((String) map.get("ExamSubjectID"));
            model.setExamSubjectName((String) map.get("ExamSubjectName"));
            model.setExamSubjectCode((String) map.get("subjectCode"));

            model.setExamPaperID(map.get("ExamPaperID").toString());
            model.setExamineeExamPaperID((String) map.get("ExamineeExamPaperID"));
            model.setExamineeResult((String)map.get("ExamineeResult"));

            List<ExamingMonitorLog> monitorLogs = examingMoniterLogMapper.findListByArrangeId(map.get("ID").toString());
            List<Behavior> behaviors = new ArrayList<>();
            for (ExamingMonitorLog log:monitorLogs) {
                Behavior behavior = new Behavior();
                behavior.setMemo(log.getMemo());
                behavior.setReason(log.getReason());
                behavior.setTypeID(log.getTypeID());
                behaviors.add(behavior);
            }

            model.setBehavior(behaviors);
            ExtendInfo extendInfo = new ExtendInfo();
            ExamPlanInfo examPlanInfo = examPlanInfoMapper.getExamPlanInfo(appId, planId);
            extendInfo.setExamplanID(examPlanInfo.getExamPlanInfoID());
            extendInfo.setExamPlanName(examPlanInfo.getExamPlanName());
            extendInfo.setAppID(adminInfo.getAppID());
            extendInfo.setExamSiteID(adminInfo.getExamSiteID());
            model.setExtendInfo(extendInfo);
            retList.add(model);

        }
        return retList;
    }


    /**
     * 统考导出
     * @param reportIds
     * @param appId
     * @param siteId
     * @param planId
     * @return
     */
    public OperationResult downloadReport(List<Integer> reportIds, String appId, String siteId, String planId) throws IOException {
        //基础根路径
        String basePath = ExamSitePath.rootPath + "/" + planId + "/"+ siteId +"/files/result/";
        //要生成的压缩文件夹路径
        String zipFilePath = basePath + DateUtil.convertDateToString(new Date());
        //结果包存放文件夹路径
        String fileFolder = basePath + String.format("%s/%s/%s/", appId, siteId, planId);

        List<String> resultPackagePathList = new ArrayList<>();
        for (Integer reportId:reportIds) {
            ExamReport examReport = examReportMapper.getExamReportById(reportId);
            if(examReport == null || examReport.getExamResult() == null || ("").equals(examReport.getExamResult())){
                return new OperationResult(OperationResultType.Warning,"对不起，所选报告不存在！");
            }
            //结果包文件路径集合
            resultPackagePathList.add(fileFolder + examReport.getExamResult());
        }

        //日志路径
        //String logFilePath =  "/logs/"+ appId + "/" + siteId + "/" + planId + "/";

        //生成压缩文件  生成文件的目录  files/result/xxx.zip
        ZipUtils.addFileToZipPackage(zipFilePath,resultPackagePathList,basePath,"");

        return new OperationResult(OperationResultType.Success,"导出报告成功！",zipFilePath + ".zip");
    }


    /**
     * 随考监考详情页面
     * @param appId
     * @param planId
     * @param subjectId
     * @param siteId
     * @param examCardNo
     * @param examineeName
     * @return
     */
    public List<ExamingMonitorViewModel> findFreeExamReportList(String appId, String planId, String subjectId, String siteId, String examCardNo, String examineeName){
        List<ExamingMonitorViewModel> retList = new ArrayList<>();

        List<Map<String, Object>> freeExamReportList = examReportMapper.findFreeExamReportList(appId, planId, subjectId, siteId,examCardNo,examineeName);
        for (Map<String, Object> map:freeExamReportList){
            ExamingMonitorViewModel model = new ExamingMonitorViewModel();
            model.setId(map.get("ID").toString());
            model.setExamCardNo((String) map.get("ExamCardNo"));
            model.setSysState((Integer) map.get("SysState"));
            model.setExamineeName((String) map.get("ExamineeName"));
            model.setExamEndTime(DateUtil.convertMillisecondToDateString(DateUtil.convertStringToDate(map.get("ExamEndTime").toString()).getTime() + ((Integer)map.get("DelayMinute"))*60*1000));
            model.setExamSubjectName((String)map.get("SubjectName"));
            model.setExamSubjectID((String) map.get("ExamSubjectID"));
            model.setExamSceneID((String) map.get("ExamSceneID"));
            model.setExamRoomID((String) map.get("ExamRoomID"));
            model.setExamineeID((String) map.get("ExamineeID"));
            model.setAccountType((Integer)map.get("AccountType"));

            List<ExamingMonitorLog> logs = examingMoniterLogMapper.findListByArrangeId(map.get("ID").toString());
            List<Behavior> behaviors = new ArrayList<>();

            for (ExamingMonitorLog log:logs) {
                Behavior behavior = new Behavior();
                behavior.setMemo(log.getMemo());
                behavior.setReason(log.getReason());
                behavior.setTypeID(log.getTypeID());
                behaviors.add(behavior);
            }
            model.setBehavior(behaviors);
            retList.add(model);
        }

        return retList;
    }

    /**
     * 查看已生成
     * @param appId
     * @param planId
     * @return
     */
    public List<Map<String,Object>> findExitFreeReportList(String appId, String planId){
        return examReportMapper.findExitFreeReportList(appId, planId);
    }

    /**
     * 随考导出
     * @param selList
     * @param appId
     * @param planId
     * @param siteId
     * @return
     */
    public OperationResult freeDownloadReport(List<FreeExamDownloadInfo> selList, String appId, String planId, String siteId) throws IOException {

        //基础根路径
        String basePath = ExamSitePath.rootPath + "/" + planId + "/"+ siteId +"/files/result/";
        //要生成的压缩文件夹路径
        String zipFilePath = basePath + DateUtil.convertDateToString(new Date());
        //结果包存放文件夹路径
        String fileFolder = basePath + String.format("%s/%s/%s/", appId, siteId, planId);

        List<String> resultPackagePathList = new ArrayList<>();
        for (FreeExamDownloadInfo freeExamDownloadInfo:selList) {
            FreeExamReport report = examReportMapper.getFreeReport(freeExamDownloadInfo.getSubjectId(), freeExamDownloadInfo.getRoomId(), planId);
            if(report == null || report.getExamResult() == null || ("").equals(report.getExamResult())){
                return new OperationResult(OperationResultType.Warning,"对不起，所选报告不存在！");
            }
            //结果包文件路径集合
            resultPackagePathList.add(fileFolder + report.getExamResult());
        }

        //日志路径
        //String logFilePath =  "/logs/"+ appId + "/" + siteId + "/" + planId + "/";

        //生成压缩文件  生成文件的目录  files/result/xxx.zip
        ZipUtils.addFileToZipPackage(zipFilePath,resultPackagePathList,basePath,"");

        return new OperationResult(OperationResultType.Success,"导出报告成功！",zipFilePath + ExtendName.ZIP.getDisplay());
    }

    public Boolean isSubjective(ItemTemplate item){
        return item.getCandidateResponses() == null || item.getCandidateResponses().isEmpty();
    }

    /**
     * 获取所有试卷
     * @param examPlanID
     * @param examSubjectID
     * @return
     */
    private Map<String,String> getAllExamPaper(String examPlanID,String examSubjectID){
        //查询所有试卷
        Map<String,String> allExamPaper = new HashMap<>();
        List<ExamPaper> examPaperList = examPaperMapper.finaAllExamPaper(examPlanID, examSubjectID);
        examPaperList.parallelStream().forEach(
                examPaper -> allExamPaper.put(examPaper.getExamPaperID(),examPaper.getExamPaperContent())
        );
        return allExamPaper;
    }

    /**
     * 获取考生试卷
     * @param openAssessmentTest
     * @param examPaperItems
     * @param examineeExamPaperID
     * @return
     */
    private TestPaperTemplate getStudentPaper(OpenAssessmentTest openAssessmentTest,List<ExamineeExamPaperItem> examPaperItems,String examineeExamPaperID) throws Exception {
        TestPaperTemplate testPaper = new TestPaperTemplate();

        int itemCount = 0;
        Double score = 0.0;
        int i = 0;

        for (OpenTestPart testPart:openAssessmentTest.getTestPartCollection()) {
            for (OpenAssessmentSection section:testPart.getAssessmentSectionCollection()) {
                score += section.getScore();
                itemCount += section.getItemCount();

                SectionTemplate sectionTemplate = new SectionTemplate();
                sectionTemplate.setScore(score);
                sectionTemplate.setIdentifier(section.getIdentifier());
                sectionTemplate.setItemCount(section.getItemCount());
                sectionTemplate.setTitle(section.getTitle());
                sectionTemplate.setItemIndex(testPaper.getSectionTemplateCollection().size()+1);

                for (OpenAssessmentItemRef itemRef:section.getAssessmentItemRefCollection()) {
                    OpenAssessmentItem questionModel = OpenAssessmentItem.createInstance(itemRef.getType());
                    String itemContent = examPaperItems.stream().filter(s -> s.getItemID().toLowerCase().equals(itemRef.getIdentifier().toLowerCase())).collect(Collectors.toList()).get(0).getItemContent();
                    questionModel.LoadFromString(itemContent,assessmentItemJAXBContext);

                    ItemTemplate temp = ICreaterFactory.getItemObject(questionModel);
                    temp.setAssessmentItemType(itemRef.getType().getIndex());
                    temp.setIdentifier(itemRef.getIdentifier());
                    temp.setExample(itemRef.isExample());
                    temp.setMedia(itemRef.getMedia());
                    temp.setSubjective(itemRef.isSubjective());
                    temp.setTitle(questionModel.getTitle());
                    temp.setWeight(itemRef.getWeight());
                    temp.setResponseDuration(itemRef.getResponseDuration());
                    temp.setQuestionAnalysis("");
                    temp.setPromptShowDuration(itemRef.getPromptShowDuration());
                    temp.setScore(itemRef.getWeight());
                    temp.setItemIndex(sectionTemplate.getItemTemplateCollection().size()+1);
                    temp.setSequenceIndex(++i);
                    temp.setCorrectResponses(ICreaterFactory.getItemResult(questionModel));

                    sectionTemplate.getItemTemplateCollection().add(temp);

                }
                testPaper.getSectionTemplateCollection().add(sectionTemplate);
            }
        }
        testPaper.setIdentifier(examineeExamPaperID);
        testPaper.setTitle(openAssessmentTest.getTitle());
        testPaper.setItemCount(itemCount);
        testPaper.setScore(score);

        return testPaper;
    }

    /**
     * 分页查询计划科目结果列表
     * @param requestBody
     * @return
     */
    public PageBean<ExamReportDTO> findFreeExamSubjectReportList(Map<String,Object> requestBody){
        String examPlanID = requestBody.get("examPlanID").toString();
        Object upload = requestBody.get("upload");
        Object examResult = requestBody.get("examResult");
        Integer currentPage = Integer.valueOf(requestBody.get("currentPage").toString());
        Integer pageSize = Integer.valueOf(requestBody.get("pageSize").toString());

        PageHelper.startPage(currentPage,pageSize,true);
        List<ExamReportDTO> reportList = examReportMapper.findFreeExamSubjectReportList(examPlanID, upload, examResult);
        reportList.parallelStream().forEach(examReportDTO -> {
            List<ExaminerSystateCount> systateCounts = examReportMapper.findExaminerCountBYSystate(examReportDTO.getExamPlanInfoID(), examReportDTO.getExamSubjectID());
            for (ExaminerSystateCount examinerSystateCount:systateCounts) {
                if(examinerSystateCount.getSysState().equals(ExamManagerState.Discipline.getPrefix())){
                    //未开考
                    examReportDTO.setUnExamCount(examinerSystateCount.getCount());
                }
                if(examinerSystateCount.getSysState().equals(ExamManagerState.Login.getPrefix())){
                    //已登录
                }
                if(examinerSystateCount.getSysState().equals(ExamManagerState.BeingNotSubmit.getPrefix())){
                    //已开考未交卷
                    examReportDTO.setExamingUnSubmitCount(examinerSystateCount.getCount());
                }
                if(examinerSystateCount.getSysState().equals(ExamManagerState.Submited.getPrefix())){
                    //已交卷
                    examReportDTO.setSubmitPaperCount(examinerSystateCount.getCount());
                }
            }

        });
        long total = ((Page) reportList).getTotal();
        PageBean<ExamReportDTO> examReportDTOPageBean = new PageBean<>(currentPage, pageSize, Long.valueOf(total).intValue());
        examReportDTOPageBean.setItems(reportList);
        return examReportDTOPageBean;
    }

    public void updateFreeExamReport(FreeExamReport freeExamReport){
        freeExamReportMapper.updateIncludeInfo(freeExamReport);
    }

}
